﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using Microsoft.TeamFoundation.VersionControl.Client;
using TfsComLib.Common;
using TfsComLib.TfsBranchLib2;
using TfsComLib.TfsConnection;

namespace TfsBranchLib2.Model
{
    /// <summary>
    ///     Obsolete, Deprecated use SourceControlBranchProvider
    ///     Сlass can provide list of TFS branches for specific trunk path
    ///     Constructor is not defined
    ///     You should set parameters before use:
    ///     VersionControlServer or TfsConnection, TrunkPath
    /// </summary>
    public class SourceBranchProvider : ISourceBranches
    {
        /// <summary>
        ///     Get branches for path in Version Control system
        ///     If input parameters is not OK should rise an exception
        /// </summary>
        /// <param name="versionControlServer">version control client instance</param>
        /// <param name="trunkPath">Tfs Trunk Path. Ex: $/ProjectName/trunk </param>
        /// <returns></returns>
        public static List<BranchData> GetTfsBranches(VersionControlServer versionControlServer, string trunkPath)
        {
            if (versionControlServer == null)
            {
                throw new Exception("Version Control Server is not defined");
            }
            if (trunkPath == null)
            {
                throw new Exception("Trunk path is not defined");
            }
            var list = new List<BranchData>();
            var branches =
                versionControlServer.QueryBranchObjects(
                    new ItemIdentifier(trunkPath, VersionSpec.Latest), RecursionType.Full);

            foreach (var current in branches)
            {
                var branchData = new BranchData
                {
                    ServerPath = current.Properties.RootItem.Item,
                    Description = current.Properties.Description,
                    Name = Regex.Match(current.Properties.RootItem.Item, "(?<=/)[^/]+?$").Value
                };
                list.Add(branchData);
            }
            return list;
        }

        #region ISourceBranches Members

        /// <summary>
        ///     Get list of branches
        /// </summary>
        /// <returns></returns>
        public List<BranchData> GetBranchList()
        {
            try
            {
                var data = GetTfsBranches(VersionControlServer, BasePath);
                ServiceStatus = string.Format("Branches count: {0}", data.Count);
                if (data.Count == 0)
                {
                    IsErrorOrConnectionProblem = true;
                }
                else
                {
                    IsErrorOrConnectionProblem = false;
                }
                return data;
            }
            catch (Exception ex)
            {
                IsErrorOrConnectionProblem = true;
                ServiceStatus = ex.Message;
                throw new TfsToolException(string.Format("Error getting branch list from TFS: {0}", ex.Message), ex);
            }
        }


        private TfsConnectionData tfsConnection;

        public TfsConnectionData TfsConnection
        {
            get
            {
                if (tfsConnection == null)
                {
                    tfsConnection = new TfsConnectionData();
                }
                return tfsConnection;
            }
            set { tfsConnection = value; }
        }


        /// <summary>
        ///     Back of Version Control Server client instance property
        /// </summary>
        private VersionControlServer versionControlServer;

        /// <summary>
        ///     Version Control Server client instance
        /// </summary>
        [XmlIgnore]
        public VersionControlServer VersionControlServer
        {
            get
            {
                if (tfsConnection != null)
                {
                    versionControlServer = TfsConnection.GetVersionControlServer();
                }
                return versionControlServer;
            }
            set
            {
                versionControlServer = value;
                NotifyPropertyChange("VersionControlServer");
            }
        }

        public void BindVersionControlServer(INotifyPropertyChanged vcsKeeper, string propertyName)
        {
            vcsKeeper.PropertyChanged += (object sender, PropertyChangedEventArgs args) =>
            {
                if (args.PropertyName == propertyName)
                {
                    VersionControlServer =
                        (VersionControlServer) vcsKeeper.GetType().GetProperty(propertyName).GetValue(vcsKeeper, null);
                }
            };
        }

        /// <summary>
        ///     Back field of TrunkPath property : Path for the trunk
        /// </summary>
        private string basePath;

        /// <summary>
        ///     Path for tfs trunk
        /// </summary>
        public string BasePath
        {
            get { return basePath; }
            set
            {
                basePath = value;
                NotifyPropertyChange("BasePath");
            }
        }

        /// <summary>
        ///     Back field of ServiceStatus property
        /// </summary>
        private string serviceStatus = string.Empty;

        /// <summary>
        ///     Service status OK - String.Empty, Else error message
        /// </summary>
        public string ServiceStatus
        {
            get { return serviceStatus; }
            set
            {
                serviceStatus = value;
                NotifyPropertyChange("ServiceStatus");
            }
        }

        /// <summary>
        ///     Back field of IsErrorOrConnectionProblem property
        /// </summary>
        private bool isErrorOrConnectionProblem;

        /// <summary>
        ///     Flag of error
        /// </summary>
        public bool IsErrorOrConnectionProblem
        {
            get { return isErrorOrConnectionProblem; }
            set
            {
                isErrorOrConnectionProblem = value;
                NotifyPropertyChange("IsErrorOrConnectionProblem");
            }
        }

        private void SetError(string message)
        {
            ServiceStatus = message;
            IsErrorOrConnectionProblem = true;
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        ///     INotifyPropertyChanged implementation
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        ///     Notify client about changing
        /// </summary>
        /// <param name="prop">Property name</param>
        private void NotifyPropertyChange(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(prop));
            }
        }

        #endregion

        #region ISourceBranches Members

        public bool EnsureTrunkSet(string path)
        {
            try
            {
                if (!AutoDetectTrunkPath(path))
                {
                    return false;
                }
                if (GetBranchList().Count > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                throw new TfsToolException("Error ensuring trunk set", ex);
            }
        }

        private bool AutoDetectTrunkPath(string path)
        {
            try
            {
                var branches = VersionControlServer.QueryRootBranchObjects(RecursionType.Full);
                if ((branches != null) && (branches.Length > 0))
                {
                    if (string.IsNullOrWhiteSpace(path))
                    {
                        BasePath = branches[0].Properties.RootItem.Item;
                    }
                    else
                    {
                        BranchObject currentBranch = null;
                        foreach (var branchObject in branches)
                        {
                            if (path.StartsWith(branchObject.Properties.RootItem.Item))
                            {
                                currentBranch = branchObject;
                            }
                        }
                        if (currentBranch == null)
                        {
                            return false;
                        }
                        while (currentBranch.Properties.ParentBranch != null)
                        {
                            var parentBranches =
                                VersionControlServer.QueryBranchObjects(currentBranch.Properties.ParentBranch,
                                    RecursionType.None);
                            if ((parentBranches != null) && (parentBranches.Length > 0))
                            {
                                currentBranch = parentBranches[0];
                            }
                            else
                            {
                                break;
                            }
                        }
                        BasePath = currentBranch.Properties.RootItem.Item;
                    }
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                SetError(string.Format("AutoDetect TrunkPath error: {0}", ex.Message));
                return false;
            }
        }

        #endregion
    }
}